package work3;

import java.util.function.IntConsumer;

public class FizzBuzz {
    private int n;
    private int current = 1;
    private final Object lock = new Object();

    public FizzBuzz(int n) {
        this.n = n;
    }

    // 能被3整除且不能被5整除，输出 "fizz"
    public void fizz(Runnable printFizz) throws InterruptedException {
        while (true) {
            synchronized (lock) {
                while (current <= n && !(current % 3 == 0 && current % 5 != 0)) {
                    lock.wait();
                }
                if (current > n) {
                    lock.notifyAll();
                    break;
                }
                printFizz.run();
                current++;
                lock.notifyAll();
            }
        }
    }

    // 能被5整除且不能被3整除，输出 "buzz"
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while (true) {
            synchronized (lock) {
                while (current <= n && !(current % 5 == 0 && current % 3 != 0)) {
                    lock.wait();
                }
                if (current > n) {
                    lock.notifyAll();
                    break;
                }
                printBuzz.run();
                current++;
                lock.notifyAll();
            }
        }
    }

    // 能被3和5都整除，输出 "fizzbuzz"
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        while (true) {
            synchronized (lock) {
                while (current <= n && !(current % 3 == 0 && current % 5 == 0)) {
                    lock.wait();
                }
                if (current > n) {
                    lock.notifyAll();
                    break;
                }
                printFizzBuzz.run();
                current++;
                lock.notifyAll();
            }
        }
    }

    // 既不能被3整除也不能被5整除，输出数字
    public void number(IntConsumer printNumber) throws InterruptedException {
        while (true) {
            synchronized (lock) {
                while (current <= n && (current % 3 == 0 || current % 5 == 0)) {
                    lock.wait();
                }
                if (current > n) {
                    lock.notifyAll();
                    break;
                }
                printNumber.accept(current);
                current++;
                lock.notifyAll();
            }
        }
    }

    public static void main(String[] args) {
        int n = 15;
        FizzBuzz fizzBuzz = new FizzBuzz(n);

        Thread threadA = new Thread(() -> {
            try {
                fizzBuzz.fizz(() -> System.out.print("fizz, "));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread threadB = new Thread(() -> {
            try {
                fizzBuzz.buzz(() -> System.out.print("buzz, "));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread threadC = new Thread(() -> {
            try {
                fizzBuzz.fizzbuzz(() -> System.out.print("fizzbuzz, "));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread threadD = new Thread(() -> {
            try {
                fizzBuzz.number(num -> System.out.print(num + ", "));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        threadA.start();
        threadB.start();
        threadC.start();
        threadD.start();
    }
}
